package org.hive.vmware.client.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hive.vmware.client.model.VmGroupVO;
import org.hive.vmware.client.model.VmGroupingVO;
import org.hive.vmware.client.model.VmVO;
import org.hive.vmware.client.service.CachedVmwareService;

import com.extjs.gxt.ui.client.Style.LayoutRegion;
import com.extjs.gxt.ui.client.Style.Scroll;
import com.extjs.gxt.ui.client.Style.SortDir;
import com.extjs.gxt.ui.client.dnd.ListViewDragSource;
import com.extjs.gxt.ui.client.dnd.ListViewDropTarget;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.IconButtonEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.StoreSorter;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.ListView;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.button.ToolButton;
import com.extjs.gxt.ui.client.widget.custom.Portal;
import com.extjs.gxt.ui.client.widget.custom.Portlet;
import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.FlowLayout;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class GroupVMPanel extends LayoutContainer {
	
	private final CachedVmwareService vmWareService = CachedVmwareService.getInstance();
	
	private Portal portal;
	private ListStore<VmVO> ungroupedVmListStore;
	private Map<VmGroupVO, ListStore<VmVO>> groupStoreMap = new HashMap<VmGroupVO, ListStore<VmVO>>();
	private List<Portlet> portlets = new ArrayList<Portlet>();
	private ListView<VmVO> ungroupedVmlist;
	
	@Override
	protected void onRender(Element parent, int index) {
		super.onRender(parent, index);
		
		setLayout(new BorderLayout());
		setHeight(600);
				
		ContentPanel ungroupedVMPanel = createUngroupedVMPanel();
		ungroupedVMPanel.setScrollMode(Scroll.AUTO);
		ungroupedVmlist = new ListView<VmVO>();
		ungroupedVmlist.setBorders(false);
		ungroupedVmlist.setHeight(500);
		new ListViewDragSource(ungroupedVmlist);
		new ListViewDropTarget(ungroupedVmlist);
		ungroupedVmlist.setDisplayProperty("description");  
		ungroupedVmListStore = new ListStore<VmVO>();  
		ungroupedVmListStore.setStoreSorter(new StoreSorter<VmVO>());  
		ungroupedVmListStore.add(createSome());  
		ungroupedVmlist.setStore(ungroupedVmListStore);
		ungroupedVMPanel.add(ungroupedVmlist);
		
		BorderLayoutData westData = new BorderLayoutData(LayoutRegion.WEST, 200, 100, 300);  
		westData.setMargins(new Margins(5, 0, 5, 5));  
		westData.setCollapsible(false);
		
		add(ungroupedVMPanel, westData);
		
		ContentPanel portalPanel = createGroupedVMPortal();
		
		BorderLayoutData centerData = new BorderLayoutData(LayoutRegion.CENTER);  
		centerData.setMargins(new Margins(5));
		add(portalPanel, centerData);
		
	}

	private ContentPanel createGroupedVMPortal() {
		portal = new Portal(3);  
		portal.setBorders(true);  
		portal.setStyleAttribute("backgroundColor", "white");  
		portal.setColumnWidth(0, .33);  
		portal.setColumnWidth(1, .33);  
		portal.setColumnWidth(2, .33);
		portal.setBorders(false);
		
		ContentPanel portalPanel = new ContentPanel();
		portalPanel.setHeaderVisible(false);
		portalPanel.setTopComponent(toolbar());
		portalPanel.setScrollMode(Scroll.AUTO);
		portalPanel.add(portal);
		portalPanel.setBodyBorder(false);
		return portalPanel;
	}

	private ContentPanel createUngroupedVMPanel() {
		ContentPanel freeVmPanel = new ContentPanel();  
		freeVmPanel.setBodyBorder(false);  
		freeVmPanel.setHeading("Ungrouped VMs");  
		freeVmPanel.setLayout(new FlowLayout());
		freeVmPanel.setBorders(false);
		return freeVmPanel;
	}

	private Portlet createPortlet(VmGroupVO vmGroupVO) {
		Portlet portlet = new Portlet(); 
		portlet.setHeading(vmGroupVO.getName());  
		ListView<VmVO> listView = createList(vmGroupVO);
		configPanel(portlet, listView.getStore());  
		portlet.setLayout(new FitLayout());
		portlet.add(listView);
		portlet.setHeight(250);
		portlets.add(portlet);
		return portlet;
	}
	
	private void removePortlets() {
		for (Portlet portlet : portlets) {
			int portletColumn = portal.getPortletColumn(portlet);
			portal.remove(portlet, portletColumn);
		}
		portlets.clear();
	}
	
	private ListView<VmVO> createList(VmGroupVO vmGroupVO) {
		ListView<VmVO> vmList = new ListView<VmVO>();
		new ListViewDragSource(vmList);
		new ListViewDropTarget(vmList);
		ListStore<VmVO> store = new ListStore<VmVO>();
		store.setStoreSorter(new StoreSorter<VmVO>());
		List<VmVO> vms = vmGroupVO.getVms();
		store.add(vms);
		vmList.setDisplayProperty("description");  
		groupStoreMap.put(vmGroupVO, store);
		vmList.setStore(store);
		vmList.setBorders(true);
		return vmList;
	}
	
	ToolBar toolbar() {
		ToolBar tb = new ToolBar();  
		Button add = new Button(" Create A New Group "); 
		add.addSelectionListener(new SelectionListener<ButtonEvent>(){
			@Override
			public void componentSelected(ButtonEvent ce) {
				final MessageBox box = MessageBox.prompt("Enter VM Group",
						"Please enter a name for new VM group:");
				box.addCallback(new Listener<MessageBoxEvent>() {
					public void handleEvent(MessageBoxEvent be) {
						if (be.getValue() == null || be.getValue().trim().isEmpty()) {
							MessageBox.alert("Alert", "Group name is empty.", new Listener<MessageBoxEvent>(){
								@Override
								public void handleEvent(MessageBoxEvent be) {
								}});
							return;
						}
						boolean duplicateNameFound = false;
						for (Portlet portlet : portlets) {
							if (portlet.getHeading().equals(be.getValue())) {
								duplicateNameFound = true;
								break;
							}
						}
						if (duplicateNameFound) {
							MessageBox.alert("Alert", "Duplicate group name is not allowed.", new Listener<MessageBoxEvent>(){
								@Override
								public void handleEvent(MessageBoxEvent be) {
								}}); 
						} else {
							VmGroupVO vmGroupVO = new VmGroupVO();
							vmGroupVO.setName(be.getValue());
							portal.insert(createPortlet(vmGroupVO), 0, 0);
						}
					}
				});  
			}});
		tb.add(add);
		Button save = new Button("Save");
		
		save.addSelectionListener(new SelectionListener<ButtonEvent>(){
			@Override
			public void componentSelected(ButtonEvent ce) {
				VmGroupingVO vmGrouping = collectVmGroups();
				
				vmWareService.saveVmGrouping(vmGrouping, new AsyncCallback<Boolean>(){

					@Override
					public void onFailure(Throwable caught) {
						Info.display("Save Group", "Unable to save vm groups");
					}

					@Override
					public void onSuccess(Boolean result) {
						if (result) {
							Info.display("Save Group", "Saved vm groups");
						} else {
							Info.display("Save Group", "Unable to save vm groups");
						}
					}});
			}});
		
		tb.add(save);
		
		return tb;
	}
	
	private VmGroupingVO collectVmGroups() {
		VmGroupingVO vmGrouping = new VmGroupingVO();
		Set<VmGroupVO> keySet = groupStoreMap.keySet();
		Iterator<VmGroupVO> groupIterator = keySet.iterator();
		while(groupIterator.hasNext()) {
			VmGroupVO vmGroup = groupIterator.next();
			ListStore<VmVO> listStore = groupStoreMap.get(vmGroup);
			vmGroup.setVms(listStore.getModels());
			vmGrouping.add(vmGroup);
		}
		return vmGrouping;
	}

	private List<VmVO> createSome() {
		List<VmVO> vos = new ArrayList<VmVO>();
		return vos;
	}
	
	private void configPanel(final Portlet panel, final ListStore<VmVO> vmStore) {  
		panel.setCollapsible(true);  
		panel.setAnimCollapse(false);  
		ToolButton revertButton = new ToolButton("x-tool-gear", new SelectionListener<IconButtonEvent>(){
			@Override
			public void componentSelected(IconButtonEvent ce) {
				 MessageBox.confirm("Confirm", "Are you sure you want to revert the vms in this group?", new Listener<MessageBoxEvent>(){
					@Override
					public void handleEvent(MessageBoxEvent be) {
						String text = be.getButtonClicked().getText();
						if ("Yes".equals(text)) {
							vmWareService.revertVms(vmStore.getModels(), new AsyncCallback<Boolean>(){

								@Override
								public void onFailure(Throwable caught) {
								}

								@Override
								public void onSuccess(Boolean result) {
									Info.display("Revert VMs", "VM reverted");
								}});
						}
							
					}});  
			}});
		revertButton.setToolTip("Revert vms in this group");
		panel.getHeader().addTool(revertButton);  
		panel.getHeader().addTool(  
		    new ToolButton("x-tool-close", new SelectionListener<IconButtonEvent>() {     
		      @Override  
		      public void componentSelected(IconButtonEvent ce) {  
		        panel.removeFromParent();
		        Iterator<VmGroupVO> iterator = groupStoreMap.keySet().iterator();
		        VmGroupVO foundGroup = null;
		        while(iterator.hasNext() && foundGroup == null) {
		        	VmGroupVO vmGroupVO = iterator.next();
		        	ListStore<VmVO> store = groupStoreMap.get(vmGroupVO);
		        	if (store.equals(vmStore)) {
		        		foundGroup = vmGroupVO;
		        	}
		        }
		        if (foundGroup != null) {
		        	groupStoreMap.remove(foundGroup);
		        }
		        ungroupedVmlist.getStore().add(vmStore.getModels());
		        portlets.remove(panel);
		      }  
		    }));  
   }  
	
	public void loadModel() {
		vmWareService.loadVmGrouping(new AsyncCallback<VmGroupingVO>(){

			@Override
			public void onFailure(Throwable caught) {
				//
				Info.display("Warning", "Fail to load vms. " + caught.getMessage());
			}

			@Override
			public void onSuccess(VmGroupingVO grouping) {
				removePortlets();
				groupStoreMap.clear();
				ungroupedVmListStore.removeAll();
				ungroupedVmListStore.add(grouping.getUngroupedVOs());
				ungroupedVmListStore.sort("description", SortDir.DESC);
				List<VmGroupVO> groupVOs = grouping.getGroupVOs();
				int i = 0;
				for (VmGroupVO vmGroupVO : groupVOs) {
					int col = i % 3;
					portal.insert(createPortlet(vmGroupVO), 0, col);
					i++;
				}
			}});
	}
}
